package org.vison.wonfu.framework.codestyle.rules.impl;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import org.vison.wonfu.framework.codestyle.config.CheckerConfig;
import org.vison.wonfu.framework.codestyle.issue.Issue;
import org.vison.wonfu.framework.codestyle.issue.IssueCollector;
import org.vison.wonfu.framework.codestyle.rules.CodeCheckRule;

import java.io.File;
import java.util.regex.Pattern;

public class DaoMethodNamingCheckRule implements CodeCheckRule {


    private static final String RULE_ID = "dao-method-naming";
    private static final String RULE_NAME = "DAO方法命名规范检查";
    private static final String RULE_DESCRIPTION = "检查Dao层方法是否符合规范";

    // DAO方法命名正则表达式
    private static final String QUERY_FIND_PATTERN = "^find(?:\\w+|$)\\w*";          // find或findBy开头
    private static final String QUERY_LIST_PATTERN = "^list(?:\\w+|$)\\w*";          // list或listBy开头
    private static final String QUERY_COUNT_PATTERN = "^count(?:\\w+|$)\\w*";        // count或countBy开头
    private static final String QUERY_EXISTS_PATTERN = "^exists(?:\\w+|$)\\w*";      // exists或existsBy开头

    private static final String COMMAND_SAVE_PATTERN = "^save(?:\\w+|$)";                // save开头
    private static final String COMMAND_CREATE_PATTERN = "^create(?:\\w+|$)";            // create开头

    private static final String COMMAND_UPDATE_PATTERN = "^update(?:\\w+|$)";      // update或updateXXX开头
    private static final String COMMAND_DELETE_PATTERN = "^delete\\w*";            // delete开头
    private static final String COMMAND_REMOVE_PATTERN = "^remove\\w*";            // remove开头

    private  boolean enabled = true;

    private boolean strict = false;

    @Override
    public String getId() {
        return RULE_ID;
    }

    @Override
    public String getName() {
        return RULE_NAME;
    }

    @Override
    public String getDescription() {
        return RULE_DESCRIPTION;
    }

    @Override
    public void initialize(CheckerConfig config) {
        this.enabled = config.isRuleEnabled(RULE_ID);
        this.strict = config.getRuleConfig(RULE_ID).isStrict();
    }

    @Override
    public boolean isStrict() {
        return strict;
    }

    @Override
    public void check(File file, CompilationUnit compilationUnit, IssueCollector collector) {
        // 只检查以Dao结尾的类
        if (!file.getName().endsWith("Dao.java")) {
            return;
        }
        compilationUnit.accept(new VoidVisitorAdapter<Void>() {
            @Override
            public void visit(MethodDeclaration method, Void arg) {
                super.visit(method, arg);
                // 跳过构造方法
                if (method.isConstructorDeclaration()) {
                    return;
                }
                if(!method.isPublic()){
                    return;
                }
                String methodName = method.getNameAsString();
                // 检查方法名是否符合任何一种DAO命名规范
                if (!isValidDaoMethodName(methodName)) {
                    int startLine = method.getRange().isPresent() ? method.getRange().get().begin.line : 0;
                    collector.addIssue(new Issue(
                            file,
                            startLine,
                            RULE_ID,
                            String.format("DAO方法名 '%s' 不符合命名规范。允许的前缀: " +
                                    "查询(find, list, count, exists), " +
                                    "新增(save, create), " +
                                    "更新(update), " +
                                    "删除(delete, remove)", methodName),
                            isStrict() ? Issue.Severity.ERROR : Issue.Severity.WARNING
                    ));
                }
            }
        },null);

    }

    /**
     * 验证DAO方法名是否符合规范
     */
    private boolean isValidDaoMethodName(String methodName) {
        return Pattern.matches(QUERY_FIND_PATTERN, methodName) ||
                Pattern.matches(QUERY_LIST_PATTERN, methodName) ||
                Pattern.matches(QUERY_COUNT_PATTERN, methodName) ||
                Pattern.matches(QUERY_EXISTS_PATTERN, methodName) ||
                Pattern.matches(COMMAND_SAVE_PATTERN, methodName) ||
                Pattern.matches(COMMAND_CREATE_PATTERN, methodName) ||
                Pattern.matches(COMMAND_UPDATE_PATTERN, methodName) ||
                Pattern.matches(COMMAND_DELETE_PATTERN, methodName) ||
                Pattern.matches(COMMAND_REMOVE_PATTERN, methodName);
    }

}
